<!DOCTYPE HTML>
<html>

<head>
	<link rel="bookmark"  type="image/x-icon"  href="/img/logo_miccall.png"/>
	<link rel="shortcut icon" href="/img/logo_miccall.png">
	
			    <title>
    Ame雨
    </title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
    <link rel="stylesheet" href="/amelin-ting/css/mic_main.css" />
    <link rel="stylesheet" href="/amelin-ting/css/dropdownMenu.css" />
    <meta name="keywords" content="Ame雨" />
    
    	<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
	 
    <noscript>
        <link rel="stylesheet" href="/amelin-ting/css/noscript.css" />
    </noscript>
    <style type="text/css">
        body:before {
          content: ' ';
          position: fixed;
          top: 0;
          background: url('/amelin-ting/img/bg.jpg') center 0 no-repeat;
          right: 0;
          bottom: 0;
          left: 0;
          background-size: cover; 
        }
    </style>

			    
  
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script async type="text/javascript" src="//cdn.bootcss.com/mathjax/2.7.1/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
  


    <script src="/amelin-ting/js/jquery.min.js"></script>
    <script src="/amelin-ting/js/jquery.scrollex.min.js"></script>
    <script src="/amelin-ting/js/jquery.scrolly.min.js"></script>
    <script src="/amelin-ting/js/skel.min.js"></script>
    <script src="/amelin-ting/js/util.js"></script>
    <script src="/amelin-ting/js/main.js"></script>
	
<meta name="generator" content="Hexo 5.4.0"></head>
    
		
<!-- Layouts -->



<!--  代码渲染  -->
<link rel="stylesheet" href="/css/prism_coy.css" />
<link rel="stylesheet" href="/css/typo.css" />
<!-- 文章页 -->
<body class="is-loading">
    <!-- Wrapper 外包 s-->
    <div id="wrapper" class="fade-in">
        <!-- Intro 头部显示 s -->
        <!-- Intro 头部显示 e -->
        <!-- Header 头部logo start -->
        <header id="header">
    <a href="/amelin-ting/" class="logo">Art Space</a>
</header>
        <!-- Nav 导航条 start -->
        <nav id="nav" class="special" >
            <ul class="menu links" >
			<!-- Homepage  主页  --> 
			<li >
	            <a href="/amelin-ting/" rel="nofollow">主页</a>
	        </li>
			<!-- categories_name  分类   --> 
	        
	        <li class="active">
	            <a href="#s1">分类</a>
	                    <ul class="submenu">
	                        <li>
	                        <a class="category-link" href="/amelin-ting/categories/Go/">Go</a></li><li><a class="category-link" href="/amelin-ting/categories/django/">django</a></li><li><a class="category-link" href="/amelin-ting/categories/drf/">drf</a></li><li><a class="category-link" href="/amelin-ting/categories/gin/">gin</a></li><li><a class="category-link" href="/amelin-ting/categories/go/">go</a></li><li><a class="category-link" href="/amelin-ting/categories/linux/">linux</a></li><li><a class="category-link" href="/amelin-ting/categories/mysql/">mysql</a></li><li><a class="category-link" href="/amelin-ting/categories/python/">python</a></li><li><a class="category-link" href="/amelin-ting/categories/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/">内网穿透</a></li><li><a class="category-link" href="/amelin-ting/categories/%E5%89%8D%E7%AB%AF/">前端</a>
	                    </ul>
	        </li>
	        
	        <!-- archives  归档   --> 
	        
	        
		        <!-- Pages 自定义   -->
		        
		        <li>
		            <a href="/about/" title="简历">
		                简历
		            </a>
		        </li>
		        
		        <li>
		            <a href="/group/" title="团队">
		                团队
		            </a>
		        </li>
		        
		        <li>
		            <a href="/gallery/" title="图库">
		                图库
		            </a>
		        </li>
		        
		        <li>
		            <a href="/tag/" title="标签">
		                标签
		            </a>
		        </li>
		        


            </ul>
            <!-- icons 图标   -->
			<ul class="icons">
                    
                    <li>
                        <a title="github" href="https://github.com/miccall" target="_blank" rel="noopener">
                            <i class="icon fa fa-github"></i>
                        </a>
                    </li>
                    
                    <li>
                        <a title="500px" href="http://500px.com" target="_blank" rel="noopener">
                            <i class="icon fa fa-500px"></i>
                        </a>
                    </li>
                    
			</ul>
</nav>

        <div id="main" >
            <div class ="post_page_title_img" style="height: 25rem;background-image: url(https://img2.baidu.com/it/u=678750791,2955497463&amp;fm=15&amp;fmt=auto);background-position: center; background-repeat:no-repeat; background-size:cover;-moz-background-size:cover;overflow:hidden;" >
                <a href="#" style="padding: 4rem 4rem 2rem 4rem ;"><h2 >Go并发编程</h2></a>
            </div>
            <!-- Post -->
            <div class="typo" style="padding: 3rem;">
                <h2 id="一、并发与并行"><a href="#一、并发与并行" class="headerlink" title="一、并发与并行"></a>一、并发与并行</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">并发：同一时间段内执行多个任务</span></span><br><span class="line"><span class="comment">并行：同一时刻执行多个任务</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">这一点在python笔记已经详细的说明区别，这里不加以介绍</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">那Go语言的并发是通过goroutine来实现，goroutine类似于线程,属于用户态的线程，我们可以根据需要创建成千上万个goroutine并发工作，这也就是Go先天的优势，其他语言都比不过。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">goroutine是由Go语言的的运行时(runtime)调度完成，而线程是操作系统完成，所以这不一样。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">Go语言还提供channel在多个goroutine间进行通信。goroutine和channel是 Go 语言秉承的 CSP（Communicating Sequential Process）并发模式的重要实现基础</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h2 id="二、goroutine-的简单使用"><a href="#二、goroutine-的简单使用" class="headerlink" title="二、goroutine 的简单使用"></a>二、goroutine 的简单使用</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 怎么使用goroutine</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Go语言中使用goroutine非常简单，只需要在调用函数的时候在前面加上go关键字，就可以为一个函数创建一个goroutine。</span></span><br><span class="line">    <span class="comment">// 一个goroutine必定对应一个函数，可以创建多个goroutine去执行相同的函数。</span></span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 启动单个goroutine 代码演示</span><br><span class="line">    <span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line">    <span class="keyword">import</span> (</span><br><span class="line">        <span class="string">&quot;fmt&quot;</span></span><br><span class="line">        <span class="string">&quot;time&quot;</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">hello</span><span class="params">(i <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">        fmt.Println(<span class="string">&quot;hello&quot;</span>, i)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i&lt;<span class="number">100000</span>; i++ &#123;</span><br><span class="line">            <span class="keyword">go</span> hello(i)</span><br><span class="line">        &#125;</span><br><span class="line">        fmt.Println(<span class="string">&quot;main&quot;</span>)</span><br><span class="line">        time.Sleep(time.Second)</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">// 足以看到并发效率有多么的高</span></span><br></pre></td></tr></table></figure>

<h2 id="三、启动多个goroutine"><a href="#三、启动多个goroutine" class="headerlink" title="三、启动多个goroutine"></a>三、启动多个goroutine</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> goroutine什么时候结束	</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    goroutine对应的的函数结束了，goroutine结束了</span></span><br><span class="line"><span class="comment">    main函数执行完了，由main函数创建的那些goroutine都结束了</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    那么怎么做到多个goroutine优雅的结束</span></span><br><span class="line"><span class="comment">    这个时候不能用sleep了，得用一个sync.WaitGroup </span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line"></span><br><span class="line"><span class="number">1.</span> 启动多个goroutine 代码演示</span><br><span class="line">        <span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line">        <span class="keyword">import</span> (</span><br><span class="line">            <span class="string">&quot;fmt&quot;</span></span><br><span class="line">            <span class="string">&quot;sync&quot;</span></span><br><span class="line">        )</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 声明变量</span></span><br><span class="line">        <span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">func</span> <span class="title">hello</span><span class="params">(i <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">            <span class="keyword">defer</span> wg.Done() <span class="comment">// goroutine结束就登记-1</span></span><br><span class="line">            fmt.Println(<span class="string">&quot;hello&quot;</span>, i)</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">            <span class="keyword">for</span> i := <span class="number">0</span>; i&lt;<span class="number">100000</span>; i++ &#123;</span><br><span class="line">                wg.Add(<span class="number">1</span>) <span class="comment">// 启动就加1</span></span><br><span class="line">                <span class="keyword">go</span> hello(i)</span><br><span class="line">            &#125;</span><br><span class="line">            wg.Wait() <span class="comment">// 等待所有登记的goroutinr结束完</span></span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure>

<h2 id="四、goroutine调度模型"><a href="#四、goroutine调度模型" class="headerlink" title="四、goroutine调度模型"></a>四、goroutine调度模型</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 简略重点概要</span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">	GMP</span></span><br><span class="line"><span class="comment">	m:n 将m个goroutine分配给n个OS线程(操作系统线程)去处理</span></span><br><span class="line"><span class="comment">	goroutine初始栈的大小为2kb</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 详细介绍</span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	OS线程一般都有固定的栈内存 2MB</span></span><br><span class="line"><span class="comment">	goroutine初始栈的大小为2kb，但是这个大小不是固定的，可以根绝情况增大和缩小</span></span><br><span class="line"><span class="comment">	goroutine栈的大小甚至都可以达到1GB+，所以在Go语言中创建10万个goroutine小意思</span></span><br><span class="line"><span class="comment">	*/</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	GMP是Go语言运行时(runtime)层面的实现，是Go语言自己实现的一套调度系统。区别于操作系统调度OS线程</span></span><br><span class="line"><span class="comment">	</span></span><br><span class="line"><span class="comment">		G就是goroutine，里面除了存在goroutine信息外，还有与所在P的绑定等信息</span></span><br><span class="line"><span class="comment">		</span></span><br><span class="line"><span class="comment">		P管理着一组goroutine队列，P里面会存储当前goroutine信息外，还有与所在P的绑定等信息</span></span><br><span class="line"><span class="comment">		P会对自己管理的goroutine队列做出调度，比如把占用CPU时间较长的goroutine暂停、运行后续的goroutine等等）</span></span><br><span class="line"><span class="comment">		P当自己的队列消费完了就去全局队列里取，如果全局队列里也消费完了会去其他P的队列里抢任务。</span></span><br><span class="line"><span class="comment">		</span></span><br><span class="line"><span class="comment">		M是Go运行时(runtime)对操作系统内核线程的虚拟，M与内核线程一般是————映射关系，一个goroutine最终是要放在M上执行的</span></span><br><span class="line"><span class="comment">		</span></span><br><span class="line"><span class="comment">	P与M一般也是一一对应的。他们的关系是:P管理着一组G加载在M上运行。当一个G长期堵塞在一个M上，runtime就会创建新的M，阻塞G所在的P会把其他的G挂载到新建的M上，等老的G阻塞完成，或者判断死亡时就会回收旧的M</span></span><br><span class="line"><span class="comment">	P的个数是通过runtime.GOMAXPROCS设定（最大256），Go1.5版本之后默认为物理线程数。 在并发量大的时候会增加一些P和M，但不会太多，切换太频繁的话得不偿失。</span></span><br><span class="line"><span class="comment">	*/</span></span><br><span class="line"></span><br><span class="line">	<span class="comment">/*</span></span><br><span class="line"><span class="comment">	单从线程调度讲，Go语言相比起其他语言的优势在于OS线程是由OS内核来调度的，goroute则是由Go运行时(runtime)自己的调度器调度的，这个调度器使用一个称为m:n调度的技术(复用/调度m个goroutine到n个OS线程)其一大特点是goroutine的调度是在用户态下完成的， 不涉及内核态与用户态之间的频繁切换，包括内存的分配与释放，都是在用户态维护着一块大的内存池， 不直接调用系统的malloc函数（除非内存池需要改变），成本比调度OS线程低很多。 另一方面充分利用了多核的硬件资源，近似的把若干goroutine均分在物理线程上， 再加上本身goroutine的超轻量，以上种种保证了go调度方面的性能。</span></span><br><span class="line"><span class="comment">	*/</span></span><br></pre></td></tr></table></figure>

<h2 id="五、channel"><a href="#五、channel" class="headerlink" title="五、channel"></a>五、channel</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> channel 是什么</span><br><span class="line">	Go语言中的channel是Go程序并发的执行体，channel就是他们之间的连接。</span><br><span class="line">	channel是一个可以让goroutine发送特定值到另一个goroutine的通信机制</span><br><span class="line">	Go语言中的channel是一个特殊的类型。通道类似队列，遵循先入先出的规则，保证收发数据的顺序</span><br><span class="line">	每一个通道都是特殊的导管，必须声明channel的时候需要为其指定元素类型，并初始化。</span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> channel声明格式</span><br><span class="line">	<span class="keyword">var</span> 变量 <span class="keyword">chan</span> 变量类型</span><br><span class="line"></span><br><span class="line"><span class="number">3.</span> 创建channel</span><br><span class="line">	通道是引用类型，空值是<span class="literal">nil</span></span><br><span class="line">	所以必须要用<span class="built_in">make</span>初始化</span><br><span class="line">	<span class="built_in">make</span>(<span class="keyword">chan</span> 元素类型 缓冲大小)</span><br><span class="line">	</span><br><span class="line"><span class="number">4.</span> channel的操作 代码演示</span><br><span class="line">    <span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line">    <span class="keyword">import</span> (</span><br><span class="line">        <span class="string">&quot;fmt&quot;</span></span><br><span class="line">        <span class="string">&quot;sync&quot;</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> a <span class="keyword">chan</span> <span class="keyword">int</span> <span class="comment">// 声明channel变量</span></span><br><span class="line">    <span class="keyword">var</span> wg sync.WaitGroup <span class="comment">// 代替sleep等待所有goroutine完成再结束程序</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">noBufChannel</span><span class="params">()</span></span> &#123;</span><br><span class="line">        a := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">int</span>) <span class="comment">// make初始化channel，但是没有设置缓冲大小</span></span><br><span class="line">        wg.Add(<span class="number">1</span>)</span><br><span class="line">        <span class="comment">// 因为没有设置缓冲区，所以我们用匿名函数在声明一个goroutine来获取这个值</span></span><br><span class="line">        <span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">            <span class="keyword">defer</span> wg.Done()</span><br><span class="line">            x := &lt;-a</span><br><span class="line">            fmt.Printf(<span class="string">&quot;获取到了a通道里的&quot;</span>, x)</span><br><span class="line">        &#125;()</span><br><span class="line">        a &lt;- <span class="number">10</span> <span class="comment">// 往a管道传输10 这个值，但是要注意咯，我们因为没有设置缓冲大小，所以会死锁！</span></span><br><span class="line">        wg.Wait()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">BufChannel</span><span class="params">()</span></span> &#123;</span><br><span class="line">        a := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">int</span>, <span class="number">2</span>) <span class="comment">// 初始化channel设置缓冲大小</span></span><br><span class="line">        a &lt;- <span class="number">10</span> <span class="comment">// 往a管道传输10 这个值</span></span><br><span class="line">        fmt.Printf(<span class="string">&quot;10 传送到了a管道&quot;</span>)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        BufChannel()</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h2 id="六、单向通道"><a href="#六、单向通道" class="headerlink" title="六、单向通道"></a>六、单向通道</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 什么是单向通道</span><br><span class="line">	只能传值或者取值</span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 单向通道的作用</span><br><span class="line">    有的时候我们会将通道作为参数在多个任务函数间传递，很多时候我们在不同的任务函数中使用通道都会对其进行限制，比如限制通道在函数中只能发送或只能接收。</span><br><span class="line"></span><br><span class="line"><span class="number">3.</span> 代码</span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">squarer</span><span class="params">(out <span class="keyword">chan</span>&lt;- <span class="keyword">int</span>, in &lt;-<span class="keyword">chan</span> <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">        <span class="keyword">for</span> i := <span class="keyword">range</span> in &#123;</span><br><span class="line">            out &lt;- i * i</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">close</span>(out)</span><br><span class="line">    &#125; <span class="comment">// out就只能传值， in只能取值，单向通道用得最多的地方在函数参数上</span></span><br></pre></td></tr></table></figure>

<h2 id="七、select多路复用"><a href="#七、select多路复用" class="headerlink" title="七、select多路复用"></a>七、select多路复用</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> <span class="keyword">select</span>用在那 是什么</span><br><span class="line">    在某些场景下我们需要同时从多个通道接收数据。通道在接收数据时，如果没有数据可以接收将会发生阻塞。</span><br><span class="line">    我们就可以使用<span class="keyword">select</span></span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 代码演示</span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        ch := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">int</span>, <span class="number">1</span>)</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">            <span class="keyword">select</span> &#123;</span><br><span class="line">            <span class="keyword">case</span> x := &lt;-ch:</span><br><span class="line">                fmt.Println(x)</span><br><span class="line">            <span class="keyword">case</span> ch &lt;- i:</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="comment">// select也是类似于Switch</span></span><br><span class="line"></span><br><span class="line"><span class="number">3.</span> <span class="keyword">select</span>的特点</span><br><span class="line">	提高代码可读性</span><br><span class="line">	可处理一个或多个channel的发送/接收操作。</span><br><span class="line">	如果多个<span class="keyword">case</span>同时满足，<span class="keyword">select</span>会随机选择一个。</span><br><span class="line">	对于没有<span class="keyword">case</span>的<span class="keyword">select</span>&#123;&#125;会一直等待，可用于阻塞main函数。</span><br></pre></td></tr></table></figure>

<h2 id="八、worker-pool"><a href="#八、worker-pool" class="headerlink" title="八、worker pool"></a>八、worker pool</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 什么是worker pool 为什么要用 </span><br><span class="line"></span><br><span class="line">	<span class="comment">// 在工作中我们通常会使用可以指定启动的goroutine数量–worker pool模式，控制goroutine的数量，防止goroutine泄漏和暴涨。</span></span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 简易代码演示</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">worker</span><span class="params">(id <span class="keyword">int</span>, jobs &lt;-<span class="keyword">chan</span> <span class="keyword">int</span>, results <span class="keyword">chan</span>&lt;- <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">        <span class="keyword">for</span> j := <span class="keyword">range</span> jobs &#123;</span><br><span class="line">            fmt.Printf(<span class="string">&quot;worker:%d start job:%d\n&quot;</span>, id, j)</span><br><span class="line">            time.Sleep(time.Second)</span><br><span class="line">            fmt.Printf(<span class="string">&quot;worker:%d end job:%d\n&quot;</span>, id, j)</span><br><span class="line">            results &lt;- j * <span class="number">2</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        jobs := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">int</span>, <span class="number">100</span>)</span><br><span class="line">        results := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">int</span>, <span class="number">100</span>)</span><br><span class="line">        <span class="comment">// 开启3个goroutine</span></span><br><span class="line">        <span class="keyword">for</span> w := <span class="number">1</span>; w &lt;= <span class="number">3</span>; w++ &#123;</span><br><span class="line">            <span class="keyword">go</span> worker(w, jobs, results)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 5个任务</span></span><br><span class="line">        <span class="keyword">for</span> j := <span class="number">1</span>; j &lt;= <span class="number">5</span>; j++ &#123;</span><br><span class="line">            jobs &lt;- j</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">close</span>(jobs)</span><br><span class="line">        <span class="comment">// 输出结果</span></span><br><span class="line">        <span class="keyword">for</span> a := <span class="number">1</span>; a &lt;= <span class="number">5</span>; a++ &#123;</span><br><span class="line">            &lt;-results</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h2 id="九、互斥锁"><a href="#九、互斥锁" class="headerlink" title="九、互斥锁"></a>九、互斥锁</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> 什么是互斥锁</span><br><span class="line">	<span class="comment">// 互斥锁是一种常用的控制共享资源访问的方法，它能够保证同时只有一个goroutine可以访问共享资源。Go语言中使用sync包的Mutex类型来实现互斥锁</span></span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> 为什么要用互斥锁</span><br><span class="line">    <span class="keyword">var</span> x <span class="keyword">int64</span></span><br><span class="line">    <span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">50000</span>; i++ &#123;</span><br><span class="line">            x = x + <span class="number">1</span></span><br><span class="line">        &#125;</span><br><span class="line">        wg.Done()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        wg.Add(<span class="number">2</span>)</span><br><span class="line">        <span class="keyword">go</span> add()</span><br><span class="line">        <span class="keyword">go</span> add()</span><br><span class="line">        wg.Wait()</span><br><span class="line">        fmt.Println(x)</span><br><span class="line">    &#125; </span><br><span class="line"><span class="comment">// 因为上述的情况，两个goroutine 都对x进行争抢，有时候就会抢到同一个x，所以结果与预期结果不符，所以需要加一个锁，来保证数据的安全性.</span></span><br><span class="line"></span><br><span class="line"><span class="number">3.</span> 代码演示互斥锁</span><br><span class="line">	<span class="comment">//使用互斥锁能够保证同一时间有且只有一个goroutine进入临界区，其他的goroutine则在等待锁；当互斥锁释放后，等待的goroutine才可以获取锁进入临界区，多个goroutine同时等待一个锁时，唤醒的策略是随机的。</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line">    <span class="keyword">import</span> (</span><br><span class="line">        <span class="string">&quot;fmt&quot;</span></span><br><span class="line">        <span class="string">&quot;sync&quot;</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> x <span class="keyword">int64</span></span><br><span class="line">    <span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line">    <span class="keyword">var</span> lock sync.Mutex</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">add</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">50000</span>; i++ &#123;</span><br><span class="line">            lock.Lock()</span><br><span class="line">            x = x + <span class="number">1</span></span><br><span class="line">            lock.Unlock()</span><br><span class="line">        &#125;</span><br><span class="line">        wg.Done()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        wg.Add(<span class="number">2</span>)</span><br><span class="line">        <span class="keyword">go</span> add()</span><br><span class="line">        <span class="keyword">go</span> add()</span><br><span class="line">        wg.Wait()</span><br><span class="line">        fmt.Println(x)</span><br><span class="line">    &#125; </span><br></pre></td></tr></table></figure>

<h2 id="十、读写互斥锁"><a href="#十、读写互斥锁" class="headerlink" title="十、读写互斥锁"></a>十、读写互斥锁</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 当我们比如在抖音里面看视频，肯定是看的居多，写的居少，所以在看的时候是不用加锁的，写的时候加锁</span></span><br><span class="line"><span class="comment">// Go语言就给了一个sync.RWMutex读写锁</span></span><br><span class="line"><span class="comment">// 读写锁分为两种：读锁和写锁。当一个goroutine获取读锁之后，其他的goroutine如果是获取读锁会继续获得锁，如果是获取写锁就会等待；当一个goroutine获取写锁之后，其他的goroutine无论是获取读锁还是写锁都会等待。</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="number">1.</span> 代码演示</span><br><span class="line">    <span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line">    <span class="keyword">import</span> (</span><br><span class="line">        <span class="string">&quot;fmt&quot;</span></span><br><span class="line">        <span class="string">&quot;sync&quot;</span></span><br><span class="line">        <span class="string">&quot;time&quot;</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> x <span class="keyword">int64</span> = <span class="number">0</span></span><br><span class="line">    <span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line">    <span class="keyword">var</span> rwlock sync.RWMutex</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">read</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="keyword">defer</span> wg.Done()</span><br><span class="line">        rwlock.RLock()</span><br><span class="line">        fmt.Println(x)</span><br><span class="line">        time.Sleep(time.Millisecond)</span><br><span class="line">        rwlock.RUnlock()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">write</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="keyword">defer</span> wg.Done()</span><br><span class="line">        rwlock.Lock()</span><br><span class="line">        x = x + <span class="number">1</span></span><br><span class="line">        time.Sleep(time.Millisecond * <span class="number">5</span>)</span><br><span class="line">        rwlock.Unlock()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        now := time.Now()</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10</span>; i++ &#123;</span><br><span class="line">            <span class="keyword">go</span> write()</span><br><span class="line">            wg.Add(<span class="number">1</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        time.Sleep(time.Second) <span class="comment">// 因为windows模拟的效果不好，所以加个sleep</span></span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">1000</span>; i++ &#123;</span><br><span class="line">            <span class="keyword">go</span> read()</span><br><span class="line">            wg.Add(<span class="number">1</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        wg.Wait()</span><br><span class="line">        fmt.Println(time.Now().Sub(now))</span><br><span class="line">    &#125;	</span><br></pre></td></tr></table></figure>

<h2 id="十一、sync-Once"><a href="#十一、sync-Once" class="headerlink" title="十一、sync.Once"></a>十一、sync.Once</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> </span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">在编程的很多场景下我们需要确保某些操作在高并发的场景下只执行一次，例如只加载一次配置文件、只关闭一次通道等。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">Go语言中的sync包中提供了一个针对只执行一次场景的解决方案–sync.Once。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">sync.Once只有一个Do方法，其签名如下：</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">func (o *Once) Do(f func()) &#123;&#125;</span></span><br><span class="line"><span class="comment">备注：如果要执行的函数f需要传递参数就需要搭配闭包来使用。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="number">2.</span> </span><br><span class="line">    <span class="keyword">var</span> icons <span class="keyword">map</span>[<span class="keyword">string</span>]image.Image</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> loadIconsOnce sync.Once</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">loadIcons</span><span class="params">()</span></span> &#123;</span><br><span class="line">        icons = <span class="keyword">map</span>[<span class="keyword">string</span>]image.Image&#123;</span><br><span class="line">            <span class="string">&quot;left&quot;</span>:  loadIcon(<span class="string">&quot;left.png&quot;</span>),</span><br><span class="line">            <span class="string">&quot;up&quot;</span>:    loadIcon(<span class="string">&quot;up.png&quot;</span>),</span><br><span class="line">            <span class="string">&quot;right&quot;</span>: loadIcon(<span class="string">&quot;right.png&quot;</span>),</span><br><span class="line">            <span class="string">&quot;down&quot;</span>:  loadIcon(<span class="string">&quot;down.png&quot;</span>),</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Icon 是并发安全的</span></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">Icon</span><span class="params">(name <span class="keyword">string</span>)</span> <span class="title">image</span>.<span class="title">Image</span></span> &#123;</span><br><span class="line">        loadIconsOnce.Do(loadIcons)</span><br><span class="line">        <span class="keyword">return</span> icons[name]</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="number">3.</span> 并发安全的单例模式</span><br><span class="line">    <span class="keyword">package</span> singleton</span><br><span class="line"></span><br><span class="line">    <span class="keyword">import</span> (</span><br><span class="line">        <span class="string">&quot;sync&quot;</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="keyword">type</span> singleton <span class="keyword">struct</span> &#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> instance *singleton</span><br><span class="line">    <span class="keyword">var</span> once sync.Once</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">GetInstance</span><span class="params">()</span> *<span class="title">singleton</span></span> &#123;</span><br><span class="line">        once.Do(<span class="function"><span class="keyword">func</span><span class="params">()</span></span> &#123;</span><br><span class="line">            instance = &amp;singleton&#123;&#125;</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="keyword">return</span> instance</span><br><span class="line"><span class="comment">// sync.Once其实内部包含一个互斥锁和一个布尔值，互斥锁保证布尔值和数据的安全，而布尔值只用来记录初始化是否完成。</span></span><br></pre></td></tr></table></figure>

<h2 id="十二、sync-map"><a href="#十二、sync-map" class="headerlink" title="十二、sync.map"></a>十二、sync.map</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">上面的代码开启少量几个goroutine的时候可能没什么问题，当并发多了之后执行上面的代码就会报fatal error: concurrent map writes错误。</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">像这种场景下就需要为map加锁来保证并发的安全性了，Go语言的sync包中提供了一个开箱即用的并发安全版map–sync.Map。开箱即用表示不用像内置的map一样使用make函数初始化就能直接使用。同时sync.Map内置了诸如Store、Load、LoadOrStore、Delete、Range等操作方法。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="number">1.</span> 代码演示</span><br><span class="line">    <span class="keyword">var</span> m = sync.Map&#123;&#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        wg := sync.WaitGroup&#123;&#125;</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">20</span>; i++ &#123;</span><br><span class="line">            wg.Add(<span class="number">1</span>)</span><br><span class="line">            <span class="keyword">go</span> <span class="function"><span class="keyword">func</span><span class="params">(n <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">                key := strconv.Itoa(n)</span><br><span class="line">                m.Store(key, n)</span><br><span class="line">                value, _ := m.Load(key)</span><br><span class="line">                fmt.Printf(<span class="string">&quot;k=:%v,v:=%v\n&quot;</span>, key, value)</span><br><span class="line">                wg.Done()</span><br><span class="line">            &#125;(i)</span><br><span class="line">        &#125;</span><br><span class="line">        wg.Wait()</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>

<h2 id="十三、atomic原子性操作"><a href="#十三、atomic原子性操作" class="headerlink" title="十三、atomic原子性操作"></a>十三、atomic原子性操作</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在上面的代码中的我们通过锁操作来实现同步。而锁机制的底层是基于原子操作的，其一般直接通过CPU指令实现。Go语言中原子操作由内置的标准库sync/atomic提供</span></span><br><span class="line"></span><br><span class="line"><span class="number">1.</span> 代码演示</span><br><span class="line">    <span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line">    <span class="keyword">import</span> (</span><br><span class="line">        <span class="string">&quot;fmt&quot;</span></span><br><span class="line">        <span class="string">&quot;sync&quot;</span></span><br><span class="line">        <span class="string">&quot;sync/atomic&quot;</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> x <span class="keyword">int64</span></span><br><span class="line">    <span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">Add</span><span class="params">()</span></span> &#123;</span><br><span class="line">        <span class="comment">// x++</span></span><br><span class="line"></span><br><span class="line">        atomic.AddInt64(&amp;x, <span class="number">1</span>)</span><br><span class="line">        wg.Done()</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        wg.Add(<span class="number">10000</span>)</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">10000</span>; i++ &#123;</span><br><span class="line">            <span class="keyword">go</span> Add()</span><br><span class="line">        &#125;</span><br><span class="line">        wg.Wait()</span><br><span class="line">        fmt.Println(x)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"><span class="number">2.</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">LoadInt32</span><span class="params">(addr *<span class="keyword">int32</span>)</span> <span class="params">(val <span class="keyword">int32</span>)</span> 读取操作</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">LoadInt64</span><span class="params">(addr *<span class="keyword">int64</span>)</span> <span class="params">(val <span class="keyword">int64</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">LoadUint32</span><span class="params">(addr *<span class="keyword">uint32</span>)</span> <span class="params">(val <span class="keyword">uint32</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">LoadUint64</span><span class="params">(addr *<span class="keyword">uint64</span>)</span> <span class="params">(val <span class="keyword">uint64</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">LoadUintptr</span><span class="params">(addr *<span class="keyword">uintptr</span>)</span> <span class="params">(val <span class="keyword">uintptr</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">LoadPointer</span><span class="params">(addr *unsafe.Pointer)</span> <span class="params">(val unsafe.Pointer)</span></span>	</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">StoreInt32</span><span class="params">(addr *<span class="keyword">int32</span>, val <span class="keyword">int32</span>)</span> 写入操作</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">StoreInt64</span><span class="params">(addr *<span class="keyword">int64</span>, val <span class="keyword">int64</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">StoreUint32</span><span class="params">(addr *<span class="keyword">uint32</span>, val <span class="keyword">uint32</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">StoreUint64</span><span class="params">(addr *<span class="keyword">uint64</span>, val <span class="keyword">uint64</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">StoreUintptr</span><span class="params">(addr *<span class="keyword">uintptr</span>, val <span class="keyword">uintptr</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">StorePointer</span><span class="params">(addr *unsafe.Pointer, val unsafe.Pointer)</span></span>	</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">AddInt32</span><span class="params">(addr *<span class="keyword">int32</span>, delta <span class="keyword">int32</span>)</span> <span class="params">(<span class="built_in">new</span> <span class="keyword">int32</span>)</span> 修改操作</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">AddInt64</span><span class="params">(addr *<span class="keyword">int64</span>, delta <span class="keyword">int64</span>)</span> <span class="params">(<span class="built_in">new</span> <span class="keyword">int64</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">AddUint32</span><span class="params">(addr *<span class="keyword">uint32</span>, delta <span class="keyword">uint32</span>)</span> <span class="params">(<span class="built_in">new</span> <span class="keyword">uint32</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">AddUint64</span><span class="params">(addr *<span class="keyword">uint64</span>, delta <span class="keyword">uint64</span>)</span> <span class="params">(<span class="built_in">new</span> <span class="keyword">uint64</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">AddUintptr</span><span class="params">(addr *<span class="keyword">uintptr</span>, delta <span class="keyword">uintptr</span>)</span> <span class="params">(<span class="built_in">new</span> <span class="keyword">uintptr</span>)</span></span>	</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SwapInt32</span><span class="params">(addr *<span class="keyword">int32</span>, <span class="built_in">new</span> <span class="keyword">int32</span>)</span> <span class="params">(old <span class="keyword">int32</span>)</span>  交换操作</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SwapInt64</span><span class="params">(addr *<span class="keyword">int64</span>, <span class="built_in">new</span> <span class="keyword">int64</span>)</span> <span class="params">(old <span class="keyword">int64</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SwapUint32</span><span class="params">(addr *<span class="keyword">uint32</span>, <span class="built_in">new</span> <span class="keyword">uint32</span>)</span> <span class="params">(old <span class="keyword">uint32</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SwapUint64</span><span class="params">(addr *<span class="keyword">uint64</span>, <span class="built_in">new</span> <span class="keyword">uint64</span>)</span> <span class="params">(old <span class="keyword">uint64</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SwapUintptr</span><span class="params">(addr *<span class="keyword">uintptr</span>, <span class="built_in">new</span> <span class="keyword">uintptr</span>)</span> <span class="params">(old <span class="keyword">uintptr</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">SwapPointer</span><span class="params">(addr *unsafe.Pointer, <span class="built_in">new</span> unsafe.Pointer)</span> <span class="params">(old unsafe.Pointer)</span></span>	</span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">CompareAndSwapInt32</span><span class="params">(addr *<span class="keyword">int32</span>, old, <span class="built_in">new</span> <span class="keyword">int32</span>)</span> <span class="params">(swapped <span class="keyword">bool</span>)</span>  比较并交换操作</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">CompareAndSwapInt64</span><span class="params">(addr *<span class="keyword">int64</span>, old, <span class="built_in">new</span> <span class="keyword">int64</span>)</span> <span class="params">(swapped <span class="keyword">bool</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">CompareAndSwapUint32</span><span class="params">(addr *<span class="keyword">uint32</span>, old, <span class="built_in">new</span> <span class="keyword">uint32</span>)</span> <span class="params">(swapped <span class="keyword">bool</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">CompareAndSwapUint64</span><span class="params">(addr *<span class="keyword">uint64</span>, old, <span class="built_in">new</span> <span class="keyword">uint64</span>)</span> <span class="params">(swapped <span class="keyword">bool</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">CompareAndSwapUintptr</span><span class="params">(addr *<span class="keyword">uintptr</span>, old, <span class="built_in">new</span> <span class="keyword">uintptr</span>)</span> <span class="params">(swapped <span class="keyword">bool</span>)</span></span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">CompareAndSwapPointer</span><span class="params">(addr *unsafe.Pointer, old, <span class="built_in">new</span> unsafe.Pointer)</span> <span class="params">(swapped <span class="keyword">bool</span>)</span></span>	</span><br></pre></td></tr></table></figure>

<h2 id="课后小作业"><a href="#课后小作业" class="headerlink" title="课后小作业"></a>课后小作业</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span></span><br><span class="line">    <span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line">    <span class="keyword">import</span> (</span><br><span class="line">        <span class="string">&quot;fmt&quot;</span></span><br><span class="line">        <span class="string">&quot;sync&quot;</span></span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line">    <span class="comment">/*</span></span><br><span class="line"><span class="comment">    有两个管道，往第一个管道添加100个值</span></span><br><span class="line"><span class="comment">    在用goroutine取出来添加到第二个管道并且把值平方</span></span><br><span class="line"><span class="comment">    再用fmt从第二个管道打印出来</span></span><br><span class="line"><span class="comment">    */</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> wg sync.WaitGroup</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">f1</span><span class="params">(c1 <span class="keyword">chan</span> <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">        <span class="keyword">defer</span> wg.Done()</span><br><span class="line">        <span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">100</span>; i++ &#123;</span><br><span class="line">            c1 &lt;- i</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">close</span>(c1) <span class="comment">// 注意必须要关闭管道</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">f2</span><span class="params">(c1, c2 <span class="keyword">chan</span> <span class="keyword">int</span>)</span></span> &#123;</span><br><span class="line">        <span class="keyword">defer</span> wg.Done()</span><br><span class="line">        <span class="keyword">for</span> num := <span class="keyword">range</span> c1 &#123;</span><br><span class="line">            c2 &lt;- num * num</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">close</span>(c2) <span class="comment">// 注意必须要关闭管道</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">        c1 := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">int</span>, <span class="number">100</span>)</span><br><span class="line">        c2 := <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="keyword">int</span>, <span class="number">100</span>)</span><br><span class="line">        wg.Add(<span class="number">2</span>)</span><br><span class="line">        <span class="keyword">go</span> f1(c1)</span><br><span class="line">        <span class="keyword">go</span> f2(c1, c2)</span><br><span class="line">        wg.Wait()</span><br><span class="line">        <span class="keyword">for</span> num := <span class="keyword">range</span> c2&#123;</span><br><span class="line">            fmt.Println(num)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>


            </div>

            <!-- Post Comments -->
            
    <!-- 使用 DISQUS_CLICK -->
<div id="disqus-comment">
    <div id="disqus_thread"></div>

<!-- add animation -->
<style>
	.disqus_click_btn {
            line-height: 30px;
            margin: 0;
            min-width: 50px;
            padding: 0 14px;
            display: inline-block;
            font-family: "Roboto", "Helvetica", "Arial", sans-serif;
            font-size: 14px;
            font-weight: 400;
            text-transform: uppercase;
            letter-spacing: 0;
            overflow: hidden;
            will-change: box-shadow;
            transition: box-shadow .2s cubic-bezier(.4, 0, 1, 1), background-color .2s cubic-bezier(.4, 0, .2, 1), color .2s cubic-bezier(.4, 0, .2, 1);
            outline: 0;
            cursor: pointer;
            text-decoration: none;
            text-align: center;
            vertical-align: middle;
            border: 0;
            background: rgba(158, 158, 158, .2);
            box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
            color: #fff;
            background-color: #7EC0EE;
            text-shadow: 0
        }
</style>
	
<div class="btn_click_load" id="disqus_bt"> 
    <button class="disqus_click_btn">点击查看评论</button>
</div>

<!--
<script type="text/javascript">
$('.btn_click_load').click(function() {
    /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
    var disqus_shortname = 'http-miccall-tech'; // required: replace example with your forum shortname

    /* * * DON'T EDIT BELOW THIS LINE * * */
    (function() {
      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();

    document.getElementById('disqus_bt').style.display = "none";
});
</script>
-->
<script type="text/javascript">
    var disqus_config = function () {
        this.page.url = 'https://gitee.com/AmeX/amelin-ting.git/2018/05/20/Go%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B------%E5%B9%B6%E5%8F%91/';  // Replace PAGE_URL with your page's canonical URL variable
        this.page.identifier = 'https://gitee.com/AmeX/amelin-ting.git/2018/05/20/Go%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B------%E5%B9%B6%E5%8F%91/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
    };
</script>

<script type="text/javascript">
    $('.btn_click_load').click(function() {  //click to load comments
        (function() { // DON'T EDIT BELOW THIS LINE
            var d = document;
            var s = d.createElement('script');
            s.src = '//http-miccall-tech.disqus.com/embed.js';
            s.setAttribute('data-timestamp', + new Date());
            (d.head || d.body).appendChild(s);
        })();
        $('.btn_click_load').css('display','none');
    });
</script>
</div>
<style>
    #disqus-comment{
        background-color: #eee;
        padding: 2pc;
    }
</style>


        </div>
        <!-- Copyright 版权 start -->
                <div id="copyright">
            <ul>
                <li>&copy;Powered By <a target="_blank" rel="noopener" href="https://hexo.io/zh-cn/" style="border-bottom: none;">hexo</a></li>
                <li>Design: <a target="_blank" rel="noopener" href="http://miccall.tech " style="border-bottom: none;">miccall</a></li>
            </ul>
            
                <span id="busuanzi_container_site_pv">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
			
        </div>
    </div>
</body>



 	
</html>
